#include "TcpServer.h"

using namespace std;

std::mutex MutexConnLst;

TcpServer::TcpServer()
{
	//ctor
	m_pBufRecv = new char[BUF_MAX_SIZE];  					// 接收缓冲区
	m_pBufSend = new char[BUF_MAX_SIZE]; 					// 发送缓冲区

	m_Client_lst.clear();

	Debug::Log("Call TcpServer::TcpServer()");

}

TcpServer::TcpServer(const TcpServer& _T)
{
	Debug::Log("TcpServer::TcpServer(Const TcpServer& _T)");
}

TcpServer::~TcpServer()
{
	//dtor
	SAFE_DELETE_ARY(m_pBufRecv);
	SAFE_DELETE_ARY(m_pBufSend);
	m_Client_lst.clear();
}

// 创建套接字地址结构 失败返回-1, 成功返回 m_listenfd
int TcpServer::Create()
{
	//cout<< "==> call  TcpServer::Create()"<< endl;

	m_listenfd = socket(AF_INET, SOCK_STREAM, 0);

	return m_listenfd;
}

// 帮顶套接字地址
int TcpServer::Bind()
{
	//cout<< "==> call  TcpServer::Bind()"<< endl;

	int opt = SO_REUSEADDR;
	setsockopt(m_listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

	// 复制套接字地址结构
	bzero(&m_Addr, sizeof(m_Addr));
	m_Addr.sin_family 		= AF_INET;
	m_Addr.sin_port 		= htons(m_port);
	m_Addr.sin_addr.s_addr 	= inet_addr(m_ip.c_str());

	// 绑定地址到监听套接字
	int ret = 0;
	ret = bind(m_listenfd, (struct sockaddr *)&m_Addr, sizeof(m_Addr));

	return ret;
}

// 将套接字置为监听状态
int TcpServer::Listen()
{
	//cout<< "==> call  TcpServer::Listen()"<< endl;

	int ret = 0;
	ret = listen(m_listenfd, MAX_CONNECT);

	return ret;
}

// 套接字初始化， 创建套接字， 并至于listen状态 成功返回0, 失败返回-1
int TcpServer::Init(std::string _ip, uint16_t _port)
{
	m_ip 	= _ip;
	m_port 	= _port;

	int ret = 0;

	ret = this->Create();
	if(-1 == ret)
	{
		Debug::Error("TcpServer::Init error when Create()");
		return -1;
	}

	ret = this->Bind();
	if(-1 == ret)
	{
		Debug::Error("TcpServer::Init error when Bind()");
		return -1;
	}

	ret = this->Listen();
	if(-1 == ret)
	{
		Debug::Error("TcpServer::Init error when Listen()");
		return -1;
	}

	Debug::State(BOLDGREEN, "TcpServer ready. IP:", RESET, BOLDWHITE, m_ip, RESET,
				BOLDGREEN, " PORT:", RESET, BOLDWHITE, m_port, RESET);

	return 0;
}

// 套接字等待链接循环
void TcpServer::ConnectLoop()
{
	fd_set Fset; 								// select recv监听的socket文件列表

	// 死循环检测socket。 select模型
	while(1)
	{
		FD_ZERO(&Fset);
		FD_SET(m_listenfd, &Fset);
		int maxFd = m_listenfd; 				// 最大fd
		struct timeval TimeOut = {0, 10}; 		// select 阻塞时间 1ms, 每次都需要赋值 YU_TODO:

		// 将所有在链接的套接字加入select范围
		for(auto& rIter : m_Client_lst)
		{
			FD_SET(rIter.m_fd, &Fset);

			if(rIter.m_fd > maxFd)
				maxFd = rIter.m_fd;
		}

		// select 检测读取 和 链接
		int retSelect = select(maxFd + 1, &Fset, NULL, NULL, &TimeOut);
		if(0 == retSelect)
		{
			continue;
		}
		else if (-1 == retSelect)
		{
			//cout<< "TcpServer::ConnectLoop() error when select()"<< endl;
			Debug::Error("TcpServer::ConnectLoop() error when select()");
			_exit(-1);
		}

		// 有新链接
		if(FD_ISSET(m_listenfd, &Fset))
		{
			this->OnNewConnect();
			continue;
		}

		// 有链接收到消息
		this->OnConnectRecvMsg(Fset);
	}
}

// 当select监听到有新链接的处理
void TcpServer::OnNewConnect()
{
	Debug::Log(__func__, " FD_SETSIZE= ", FD_SETSIZE, ". connect count:", m_Client_lst.size());

	unsigned int limit = min(FD_SETSIZE, MAX_CONNECT);
	if(m_Client_lst.size() >= limit)
	{
		//cout<< "sorry. at the max of sock connect's Count "<< FD_SETSIZE<< endl;
		Debug::Error("Sorry. at the max of sock connect's Count ", FD_SETSIZE);
		return;
	}

	SockAddr4 ConnAddr; 								// 新的链接套接字地址
	socklen_t len = sizeof(ConnAddr); 					// 套接字地址长度
	bzero(&ConnAddr, sizeof(len));

	// 接受链接
	int connFd = 0; 									// 链接套接字
	connFd = accept(m_listenfd, (struct sockaddr *)&ConnAddr, &len);
	if(-1 == connFd)
	{
		//cout<< "==> TcpServer::OnNewConnect() error when accept()"<< endl;
		Debug::Error(__func__, " When accept()");
		//sleep(1);
		return;
	}

	// 保存新链接信息
	Client C(connFd);
	C.m_ip = inet_ntoa(ConnAddr.sin_addr);
	C.m_port = ConnAddr.sin_port;

	MutexConnLst.lock();
	m_Client_lst.push_back(C);
	MutexConnLst.unlock();

	//cout<< "==> Connect successd. Client's count:"<< m_Client_lst.size()<< endl;
	Debug::Log("Connect successd. Client's count:", m_Client_lst.size());

//	iter->m_askTimes = iter->m_askTimes + 1;
	C.m_askTimes++;
	Message Msg1(C.m_fd, eCmd::SYS_Check_Ask);
	int key = 9527;
	Msg1.AddInt(key);
	Message::Send(&this->GetMsgQunue(), &Msg1);
	//Debug::Log("Send Msg eCmd::SYS_Check_Ask");

}



// 当select监听到有链接收到消息
void TcpServer::OnConnectRecvMsg(fd_set & _Fset)
{
	bool isCloseConn = false;
	//int shutdownFd = 0;
	std::list<int> shutdownFd_lst;
	std::list<Client>::iterator dleteIter = m_Client_lst.begin();
	std::list<Client>::iterator iter = dleteIter;
	for(; iter != m_Client_lst.end(); iter++)
	{
		int connFd = iter->m_fd;

		if(!FD_ISSET(connFd, &_Fset))
			continue;

		/// 找到有消息的链接了
		//std::cout<< "sizeof(m_pBufRecv): "<< sizeof(m_pBufRecv)<<endl;
		memset(&m_pBufRecv[0], 0, BUF_MAX_SIZE/*sizeof(m_pBufRecv)*/); 		// 接受缓冲区清空
		size_t recvLen = 0;
		recvLen = (size_t)recv(connFd, &m_pBufRecv[0], BUF_MAX_SIZE, 0);
		if(recvLen >= BUF_MAX_SIZE)
		{
			//std::cout<< "==>the msg len beyond limit: \t"<< BUF_MAX_SIZE<< endl;
			Debug::Error("The msg len beyond limit: \t", BUF_MAX_SIZE);
			continue;
		}
		else if(recvLen == 0) 					// 如果等于0 关闭链接
		{
			isCloseConn = true;
			shutdownFd_lst.push_back(connFd);
			dleteIter = iter;
			continue;
		}

		//std::cout<< "==> u got msg:\t"<< m_pBufRecv<< "\tlen:"<< recvLen<< endl;
//		Debug::Log("U got msg:\t", m_pBufRecv, "\tlen:", recvLen);

		// 解包处理
		this->UnpackAndPushInQunue(connFd, recvLen);
	}

	if(isCloseConn)
	{
		for(int fd:shutdownFd_lst)
		{
			this->ShutDownAConnect(fd);
		}

		shutdownFd_lst.clear();
	}
}

void TcpServer::Send(Message* _pMsg){
	// YU_TODO: 是否需要单独开个线程来处理

	int sendLen = _pMsg->m_len + 4;
//	memset(&m_pBufSend[0], 0, sizeof(m_pBufSend)); 		// 发送缓冲区清空
//	memcpy(&m_pBufSend[0], _pMsg->GetBuf(), sendLen);

	send(_pMsg->m_fd, _pMsg->GetBuf(), sendLen, 0);

//	Debug::Log("Send a msg, fd:", _pMsg->m_fd, " \tcmd:", (int)_pMsg->m_cmd,
//				" \tlen:", _pMsg->m_len);
}

// 关闭监听套接字
int TcpServer::Close()
{
	//cout<< "==> call  TcpServer::Close()"<< endl;
	Debug::State("TcpServer::Close()");

	close(m_listenfd);
	return 0;
}

// 关闭某个链接套接字
int TcpServer::ShutDownAConnect(int _fd)
{
	//cout<< "==> call  TcpServer::Close()"<< endl;
	Debug::State("TcpServer::ShutDownAConnect()");

	// YU_TODO: 在这里处理断开链接， 链接列表排除在检测的时候就处理了
	MutexConnLst.lock();  // YU_TODO: DELETE if in the same thread
	for(list<Client>::iterator iter = m_Client_lst.begin(); iter != m_Client_lst.end();)// Client C: m_Client_lst)
	{
		if(iter->m_fd == _fd)
		{
			m_Client_lst.erase(iter);
			break;
		}
		else
		{
			iter++;
		}
	}
	MutexConnLst.unlock();

	// 收发都关闭
	shutdown(_fd, SHUT_RDWR);
	return 0;
}

void TcpServer::SetMsgQunue(MsgQunue* ptr){
    m_MsgQunue = *ptr;
}

MsgQunue& TcpServer::GetMsgQunue(){
	return m_MsgQunue;
}



void TcpServer::UnpackAndPushInQunue(int _fd, size_t _recvLen)
{
	/* 包描述 cmd + 内容 才是真真的消息
	-------------------------------------------------------------
	| 0x02 0x02 | len | cmd | ********内容********** | 0x03 0X03 |
	-------------------------------------------------------------
		  2B       4B    4B          len-8B              2B

	测试数据：02 02 31 30 30 32 30 32 48 65 6C 6C 6F 20 03 03 0D
	*/

	const size_t packetBeginLen = 2;
	const size_t packetEndLen = 2;
	const size_t lenLen = 4;

	const size_t contentLenLimit = MSG_LEN_MAX;

	const char packetBegin 	= '\2'; 		// 双左斜杠表示包开始
	const char packetEnd 	= '\3'; 		// 双右斜杠表示包结束
	size_t pos 	= 0;

	while(pos+4 < _recvLen) 				//	//判断 包是否已经读完
	{
		// 判断包头
		if((m_pBufRecv[pos] != packetBegin) || (m_pBufRecv[pos+1] != packetBegin)) 		// 开始符 2B
		{
			//std::cout<< "a bad package. begin error."<< endl;
			Debug::Error("TcpServer. A bad package. begin error.");
			return;
		}

		alen lensss;
		memcpy(lensss.a, &m_pBufRecv[pos + packetBeginLen], lenLen);
		int len = lensss.i;
		size_t msgTotalLen = len + packetBeginLen + packetEndLen;

		// 如果一个包长度大于contentLenLimit 就被认为是坏包被抛弃掉
		if(msgTotalLen > contentLenLimit)
		{
//			std::cout<< "u got a bad package. len ="<< msgTotalLen<< "beyond "
//			<< contentLenLimit<<endl;
			Debug::Error("U got a bad package. len =", msgTotalLen, "beyond ", contentLenLimit);
			return;
		}

		char msgBuf[contentLenLimit] = {0};
		memcpy(msgBuf, &m_pBufRecv[pos], msgTotalLen);

		// 判断包尾
		pos += msgTotalLen - packetEndLen;
		int endIndex = pos;
		//cout<< "endIndex: "<< endIndex<<endl;

		if((m_pBufRecv[endIndex] == packetEnd) && (m_pBufRecv[endIndex+1] == packetEnd))
		{
			Message Msg(_fd);
			Msg.Decode(msgBuf, msgTotalLen);

			m_MsgQunue.PushRecvMsg(Msg);
		}
		else
		{
			//std::cout<< "a bad package. end error.. len ="<< msgTotalLen<< endl;
			Debug::Error("a bad package. end error.. len =", msgTotalLen);
			return ;
		}

	}

}

list<Client>& TcpServer::GetClientList()
{
	return m_Client_lst;
}

// 获取某个socket客户端
Client* TcpServer::GetClient(int _fd)
{
	for(list<Client>::iterator iter = m_Client_lst.begin();iter != m_Client_lst.end(); iter++)
	{
		if(iter->m_fd == _fd)
		{
			return &(*iter);
		}
	}

//	for(Client C: m_Client_lst)
//	{
//		if(C.m_fd == _fd)
//		{
//			return &C;
//		}
//	}

	Debug::Error("Not found the Client from TcpServer, _fd:", _fd);
	return nullptr;
}

int TcpServer::GetPort()
{
	return m_port;
}

string TcpServer::GetIp()
{
	return m_ip;
}




